package internal

import (
	"reflect"
	"time"
)

// -----------------------------------------------------
// Valid Is验证函数Copy自gitee.com/gousing/helper/valid
// -----------------------------------------------------
// Zero 返回指定Any类型的零值
func Zero[T any]() T {
	var zero T
	return zero
}

// IsZero 判断对象是否为零值
//   - 约定为零值:  nil, 为nil的任何指针
//   - 约定为非零值:  struct{}, 不为nil的指针, 不可比较类型
func IsZero(v any) bool {
	if v == nil {
		return true
	}
	// 尝试先通过断言检查基本类型的零值
	switch vs := v.(type) {
	case string:
		return vs == ""
	case bool:
		return !vs
	case int:
		return vs == 0
	case int8:
		return vs == 0
	case int16:
		return vs == 0
	case int32: // rune
		return vs == 0
	case int64:
		return vs == 0
	case uint:
		return vs == 0
	case uint8: // byte
		return vs == 0
	case uint16:
		return vs == 0
	case uint32:
		return vs == 0
	case uint64:
		return vs == 0
	case uintptr:
		return vs == 0
	case float32:
		return vs == 0
	case float64:
		return vs == 0
	case complex64:
		return vs == 0
	case complex128:
		return vs == 0
	case error:
		return vs == nil
	case struct{}:
		return false
	case time.Time:
		return vs.IsZero()
	case time.Duration:
		return vs == 0
	case time.Month:
		return vs == 0
	case time.Weekday:
		return vs == 0
	case *string:
		return vs == nil
	case *bool:
		return vs == nil
	case *int:
		return vs == nil
	case *int8:
		return vs == nil
	case *int16:
		return vs == nil
	case *int32:
		return vs == nil
	case *int64:
		return vs == nil
	case *uint:
		return vs == nil
	case *uint8:
		return vs == nil
	case *uint16:
		return vs == nil
	case *uint32:
		return vs == nil
	case *uint64:
		return vs == nil
	case *uintptr:
		return vs == nil
	case *float32:
		return vs == nil
	case *float64:
		return vs == nil
	case *complex64:
		return vs == nil
	case *complex128:
		return vs == nil
	case *error:
		return vs == nil
	case *struct{}:
		return vs == nil
	case *time.Time:
		return vs == nil
	case *time.Duration:
		return vs == nil
	case *time.Month:
		return vs == nil
	case *time.Weekday:
		return vs == nil
	case []string:
		return vs == nil
	case []bool:
		return vs == nil
	case []int:
		return vs == nil
	case []int8:
		return vs == nil
	case []int16:
		return vs == nil
	case []int32: // []rune
		return vs == nil
	case []int64:
		return vs == nil
	case []uint:
		return vs == nil
	case []uint8: // []byte
		return vs == nil
	case []uint16:
		return vs == nil
	case []uint32:
		return vs == nil
	case []uint64:
		return vs == nil
	case []uintptr:
		return vs == nil
	case []float32:
		return vs == nil
	case []float64:
		return vs == nil
	case []complex64:
		return vs == nil
	case []complex128:
		return vs == nil
	case []time.Time:
		return vs == nil
	case []time.Duration:
		return vs == nil
	case []time.Month:
		return vs == nil
	case []time.Weekday:
		return vs == nil
	case map[string]any:
		return vs == nil
	case map[string]string:
		return vs == nil
	case map[string]int:
		return vs == nil
	case map[int]any:
		return vs == nil
	case map[int]string:
		return vs == nil
	case map[int]int:
		return vs == nil
	}
	rv := reflect.ValueOf(v)
	// reflect func (v Value) IsZero() bool
	switch rv.Kind() {
	case
		reflect.Chan, reflect.Func,
		reflect.Interface, reflect.Map,
		reflect.Pointer, reflect.Slice, reflect.UnsafePointer:
		// Chan, Func, Interface, Map, Pointer(Ptr), Slice, UnsafePointer
		return rv.IsNil()
	case reflect.String, reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64,
		reflect.Complex64, reflect.Complex128,
		reflect.Array, reflect.Struct:
		return rv.IsZero()
	default:
		rt := rv.Type()
		if !rt.Comparable() {
			return false
		}
		return v == reflect.Zero(rt).Interface()
	}
}

// IsNil 判断 any 对象是否为 nil
func IsNil(v any) bool {
	if v == nil {
		return true
	}
	value := reflect.ValueOf(v)
	switch value.Kind() {
	case
		reflect.Chan, reflect.Func,
		reflect.Interface, reflect.Map,
		reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
		return value.IsNil()
	}
	return false
}

// IsEmpty 判断 any 对象是否为空
//   - 空值检查：如果输入值为 nil或nil 指针，函数返回 true。
//   - 指针处理：如果值是指针类型，函数会递归地解引用指针，直到找到非指针类型或遇到 nil 指针。
//   - 集合类型：对于数组、映射、切片和字符串，函数检查其长度是否为零。
//   - 基本类型：对于布尔值、整数、浮点数、接口和指针，函数使用 reflect.Value 的 IsZero 方法来判断其是否为空。
//   - 默认情况：对于未明确处理的其他类型，函数返回 false。
func IsEmpty(v any) bool {
	if v == nil {
		return true
	}
	// 尝试先通过断言检查基本类型的零值
	switch vs := v.(type) {
	case string:
		return vs == ""
	case bool:
		return !vs
	case int:
		return vs == 0
	case int8:
		return vs == 0
	case int16:
		return vs == 0
	case int32:
		return vs == 0
	case int64:
		return vs == 0
	case uint:
		return vs == 0
	case uint8:
		return vs == 0
	case uint16:
		return vs == 0
	case uint32:
		return vs == 0
	case uint64:
		return vs == 0
	case uintptr:
		return vs == 0
	case float32:
		return vs == 0
	case float64:
		return vs == 0
	case complex64:
		return vs == 0
	case complex128:
		return vs == 0
	case error:
		return vs == nil
	case struct{}:
		return false
	case time.Time:
		return vs.IsZero()
	case time.Duration:
		return vs == 0
	case time.Month:
		return vs == 0
	case time.Weekday:
		return vs == 0
	case *string:
		return vs == nil
	case *bool:
		return vs == nil || !(*vs)
	case *int:
		return vs == nil || *vs == 0
	case *int8:
		return vs == nil || *vs == 0
	case *int16:
		return vs == nil || *vs == 0
	case *int32:
		return vs == nil || *vs == 0
	case *int64:
		return vs == nil || *vs == 0
	case *uint:
		return vs == nil || *vs == 0
	case *uint8:
		return vs == nil || *vs == 0
	case *uint16:
		return vs == nil || *vs == 0
	case *uint32:
		return vs == nil || *vs == 0
	case *uint64:
		return vs == nil || *vs == 0
	case *uintptr:
		return vs == nil || *vs == 0
	case *float32:
		return vs == nil || *vs == 0
	case *float64:
		return vs == nil || *vs == 0
	case *complex64:
		return vs == nil || *vs == 0
	case *complex128:
		return vs == nil || *vs == 0
	case *error:
		return vs == nil || *vs == nil
	case *struct{}:
		return vs == nil
	case *time.Time:
		return vs == nil || (*vs).IsZero()
	case *time.Duration:
		return vs == nil || *vs == 0
	case *time.Month:
		return vs == nil || *vs == 0
	case *time.Weekday:
		return vs == nil || *vs == 0
	}
	rv := reflect.ValueOf(v)
	for rv.Kind() == reflect.Ptr {
		if rv.IsNil() {
			return true
		}
		rv = rv.Elem()
	}
	switch rv.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return rv.Len() == 0
	case reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64,
		reflect.Interface, reflect.Pointer:
		return rv.IsZero()
	}
	return false
}
